package com.studyweb.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 阿里云OSS文件上传工具类
 * 
 * @author StudyWeb Team
 * @since 1.0.0
 */
@Slf4j
@Component
public class AliyunOssUtils {
    
    @Autowired
    private AliyunOssProperties ossProperties;
    
    @Autowired
    private FileUploadProperties fileUploadProperties;
    
    /**
     * 上传文件到阿里云OSS
     * 
     * @param file 上传的文件
     * @return 上传结果信息
     * @throws IOException IO异常
     */
    public Map<String, Object> uploadFile(MultipartFile file) throws IOException {
        Map<String, Object> result = new HashMap<>();
        
        // 检查文件是否为空
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }
        
        // 获取原始文件名
        String originalFileName = file.getOriginalFilename();
        if (originalFileName == null || originalFileName.trim().isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        // 检查文件类型
        if (!fileUploadProperties.isAllowedType(originalFileName)) {
            throw new IllegalArgumentException("不支持的文件类型");
        }
        
        // 检查文件大小
        long fileSize = file.getSize();
        long maxSizeBytes = fileUploadProperties.getMaxSize() * 1024 * 1024; // 转换为字节
        if (fileSize > maxSizeBytes) {
            throw new IllegalArgumentException("文件大小超过限制");
        }
        
        // 生成新的文件名
        String fileExtension = fileUploadProperties.getFileExtension(originalFileName);
        String newFileName = generateFileName(fileExtension);
        
        // 根据文件类型构建OSS对象键（文件路径）
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        String subPath = "";
        if (fileUploadProperties.isImageFile(originalFileName)) {
            subPath = fileUploadProperties.getImagePath();
        } else if (fileUploadProperties.isDocumentFile(originalFileName)) {
            subPath = fileUploadProperties.getDocumentPath();
        } else {
            subPath = "others/";
        }
        String objectKey = ossProperties.getDirPrefix() + subPath + datePath + "/" + newFileName;
        
        OSS ossClient = null;
        try {
            // 创建OSS客户端
            ossClient = new OSSClientBuilder().build(
                ossProperties.getEndpoint(),
                ossProperties.getAccessKeyId(),
                ossProperties.getAccessKeySecret()
            );
            
            // 设置文件元数据
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileSize);
            metadata.setContentType(file.getContentType());
            metadata.setContentDisposition("inline;filename=" + originalFileName);
            
            // 上传文件
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                ossProperties.getBucketName(),
                objectKey,
                file.getInputStream(),
                metadata
            );
            
            ossClient.putObject(putObjectRequest);
            
            // // 设置文件为公共读取权限，以便阿里云AI可以访问
            // ossClient.setObjectAcl(ossProperties.getBucketName(), objectKey, CannedAccessControlList.PublicRead);
            
            // 构建访问URL
            String accessUrl = "https://" + ossProperties.getBucketName() + "." + 
                             ossProperties.getEndpoint().replace("https://", "").replace("http://", "") + 
                             "/" + objectKey;
            
            // 返回结果
            result.put("success", true);
            result.put("uploadMethod", "oss");
            result.put("originalName", originalFileName);
            result.put("fileName", newFileName);
            result.put("filePath", objectKey);
            result.put("fileSize", fileSize);
            result.put("fileType", file.getContentType());
            result.put("fileExt", fileExtension);
            result.put("accessUrl", accessUrl);
            
            log.info("文件上传成功: {}, OSS路径: {}", originalFileName, objectKey);
            
        } catch (Exception e) {
            log.error("文件上传失败: {}, 错误: {}", originalFileName, e.getMessage());
            result.put("success", false);
            result.put("error", e.getMessage());
            throw new IOException("文件上传失败: " + e.getMessage(), e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        
        return result;
    }
    
    /**
     * 删除OSS中的文件
     * 
     * @param objectKey OSS对象键（文件路径）
     * @return 删除是否成功
     */
    public boolean deleteFile(String objectKey) {
        if (objectKey == null || objectKey.trim().isEmpty()) {
            log.warn("删除文件失败：文件路径为空");
            return false;
        }
        
        OSS ossClient = null;
        try {
            // 创建OSS客户端
            ossClient = new OSSClientBuilder().build(
                ossProperties.getEndpoint(),
                ossProperties.getAccessKeyId(),
                ossProperties.getAccessKeySecret()
            );
            
            // 删除文件
            ossClient.deleteObject(ossProperties.getBucketName(), objectKey);
            
            log.info("文件删除成功: {}", objectKey);
            return true;
            
        } catch (Exception e) {
            log.error("文件删除失败: {}, 错误: {}", objectKey, e.getMessage());
            return false;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
    
    /**
     * 检查文件是否存在
     * 
     * @param objectKey OSS对象键（文件路径）
     * @return 文件是否存在
     */
    public boolean fileExists(String objectKey) {
        if (objectKey == null || objectKey.trim().isEmpty()) {
            return false;
        }
        
        OSS ossClient = null;
        try {
            // 创建OSS客户端
            ossClient = new OSSClientBuilder().build(
                ossProperties.getEndpoint(),
                ossProperties.getAccessKeyId(),
                ossProperties.getAccessKeySecret()
            );
            
            // 检查文件是否存在
            boolean exists = ossClient.doesObjectExist(ossProperties.getBucketName(), objectKey);
            
            log.debug("文件存在性检查: {}, 结果: {}", objectKey, exists);
            return exists;
            
        } catch (Exception e) {
            log.error("检查文件存在性失败: {}, 错误: {}", objectKey, e.getMessage());
            return false;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
    
    /**
     * 获取文件内容
     * 
     * @param objectKey OSS对象键（文件路径）
     * @return 文件内容字节数组
     * @throws IOException IO异常
     */
    public byte[] getFileContent(String objectKey) throws IOException {
        if (objectKey == null || objectKey.trim().isEmpty()) {
            throw new IllegalArgumentException("文件路径不能为空");
        }
        
        OSS ossClient = null;
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        
        try {
            // 创建OSS客户端
            ossClient = new OSSClientBuilder().build(
                ossProperties.getEndpoint(),
                ossProperties.getAccessKeyId(),
                ossProperties.getAccessKeySecret()
            );
            
            // 获取文件对象
            OSSObject ossObject = ossClient.getObject(ossProperties.getBucketName(), objectKey);
            inputStream = ossObject.getObjectContent();
            
            // 读取文件内容
            outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            
            byte[] content = outputStream.toByteArray();
            log.info("文件内容获取成功: {}, 大小: {} bytes", objectKey, content.length);
            
            return content;
            
        } catch (Exception e) {
            log.error("获取文件内容失败: {}, 错误: {}", objectKey, e.getMessage());
            throw new IOException("获取文件内容失败: " + e.getMessage(), e);
        } finally {
            // 关闭资源
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.warn("关闭输出流失败: {}", e.getMessage());
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.warn("关闭输入流失败: {}", e.getMessage());
                }
            }
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
    
    /**
     * 生成唯一文件名
     * 
     * @param fileExtension 文件扩展名
     * @return 唯一文件名
     */
    private String generateFileName(String fileExtension) {
        return UUID.randomUUID().toString().replace("-", "") + fileExtension;
    }
}